#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define SA struct sockaddr
#define SERV_PORT 8081
#define MAXLINE 4096

//https://www.cnblogs.com/soldierback/p/10701684.html

int max(int, int);
void proSession(FILE*, int, const struct sockaddr*);
ssize_t writen(int, const void*, size_t);
char *sock_ntop(const struct sockaddr*, socklen_t);

int main(int argc, char *argv[]) {
    pid_t childpid;
    int sockfd;
    struct sockaddr_in servaddr;

    if (argc != 2) {
        printf("usage: %s <IPaddress>\n", argv[0]);
        exit(-1);
    }
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == 0) {
        proSession(stdin, sockfd, (SA *)&servaddr); /* 处理会话 */
    }

    exit(0);
}

void proSession(FILE *fp, int sockfd, const struct sockaddr* addr) {
    int maxfdp1, stdineof;
    fd_set rset;
    char buf[MAXLINE];
    int n;

    stdineof = 0; 
    FD_ZERO(&rset);
    for ( ; ; ) {
        if (stdineof == 0) {
            FD_SET(fileno(fp), &rset);
        }
        FD_SET(sockfd, &rset);
        maxfdp1 = max(fileno(fp), sockfd) + 1;
        select(maxfdp1, &rset, NULL, NULL, NULL);

        if (FD_ISSET(sockfd, &rset)) {    /* 套接字描述符就绪 */
            if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
                if (stdineof == 1) {
                    return;
                } else {
                    exit(0);
                }
            }
            printf("%s\n", sock_ntop(addr, sizeof(addr)));
            write(fileno(stdout), buf, n);
            printf("\n");
        }
        if (FD_ISSET(fileno(fp), &rset)) { /* 输入描述符就绪 */
            if ( (n = read(fileno(fp), buf, MAXLINE)) == 0) {
                stdineof = 1;
                shutdown(sockfd, SHUT_WR); /* 发送 FIN */
                FD_CLR(fileno(fp), &rset);
                continue;
            }
            writen(sockfd, buf, n);
        }
    }
}

int max(int numberone, int numbertwo) {
    return ( (numberone >= numbertwo)?numberone:numbertwo);
}
